﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;

namespace SPHealth.SharePoint.HealthRules.SP.Rules.Performance
{
    public class WarnAutoGrowthSettings : SPHealthAnalysisRule
    {
        #region Locals
        private const string ruleTitle = "WarnAutoGrowthSettings";
        private const string IgnoreList = "IgnoreList";
        private StringBuilder _failingContentDatabases;
        private int _numFailingDatabases = 0;
        private SPHealthAnalysisRuleAutomaticExecutionParameters _executionParameters;

        #region SQL queries
        private const string GET_DATABASE_AUTOGROWTH_SETTINGS =
                "SELECT type, name, is_percent_growth, CASE WHEN type = 0 THEN LTRIM(STR(growth * 8.0 / 1024,10,1)) ELSE CAST(growth AS VARCHAR) END as growth, max_size  FROM sys.database_files with (nolock)";
        #endregion

        #endregion

        #region Constructor
        public WarnAutoGrowthSettings()
        {
            _failingContentDatabases = new StringBuilder();
            _numFailingDatabases = 0;
        }
        #endregion

        #region Fields

        public override string Summary
        {
            get { return "One or more Content Databases are currently using the default autogrowth settings."; }
        }

        public override string Explanation
        {
            get
            {
                return String.Format("The following {0}Content Database{1} currently using the default autogrowth settings:\r\n\r\n{2}",
                    _numFailingDatabases > 1 ? _numFailingDatabases.ToString() + " " : "",
                    _numFailingDatabases > 1 ? "s are" : " is",
                    _failingContentDatabases.ToString());
            }
        }

        public override string Remedy
        {
            get { return "Proactive managment of database growth is recommend including as much as possible, the pre-growth of all data and log files to their anticipated final size. See Storage and SQL Server capacity planning and configuration (SharePoint Server 2010) for further details: http://technet.microsoft.com/en-us/library/cc298801.aspx"; }
        }

        public override SPHealthCheckErrorLevel ErrorLevel
        {
            get { return SPHealthCheckErrorLevel.Warning; }
        }

        public override SPHealthCategory Category
        {
            get { return SPHealthCategory.Performance; }
        }

        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                if (_executionParameters == null)
                {
                    _executionParameters = new SPHealthAnalysisRuleAutomaticExecutionParameters
                    {
                        Schedule = SPHealthCheckSchedule.Daily,
                        Scope = SPHealthCheckScope.Any,
                        ServiceType = typeof(SPTimerService), //Tell SP if we want our own timer job or can we run with others...
                        RepairAutomatically = false
                    };
                }
                return _executionParameters;
            }
        }

        #endregion

        #region Methods

        // used to provide the configuration list item title
        public static string GetTitle()
        {
            // return the title for the rule
            return ruleTitle;
        }

        // used to provide the default configuration settings
        public static IDictionary<string, string> GetDefaultSettings()
        {
            // return the default settings for the rule
            IDictionary<string, string> settings = new Dictionary<string, string>();
            settings.Add("Comment1", "Enter a semi-colon delimited list of database names");
            settings.Add("Comment2", "that should be excluded from this check.");
            settings.Add(IgnoreList, "");
            return settings;
        }

        public override SPHealthCheckStatus Check()
        {
            if (!SPFarm.Joined)
            {
                throw new InvalidOperationException();
            }

            SPHealthCheckStatus status = SPHealthCheckStatus.Passed;

            foreach (SPWebApplication webApplication in SPWebService.ContentService.WebApplications)
            {
                if (webApplication.Status == SPObjectStatus.Online)
                {
                    foreach (SPContentDatabase contentDatabase in webApplication.ContentDatabases)
                    {
                        try
                        {
                            string dbAutoGrowthSetting = GetContentDatabaseAutoGrowthSettings(contentDatabase);
                            if (!string.IsNullOrEmpty(dbAutoGrowthSetting))
                            {
                                status = SPHealthCheckStatus.Failed;
                                _numFailingDatabases++;
                                _failingContentDatabases.AppendLine(String.Format("{0} ({1}) ",
                                                                contentDatabase.Name,
                                                                dbAutoGrowthSetting));
                            }
                        }
                        catch { /*Best effort*/ }
                    }
                }
            }

            return status;
        }

        private static string GetContentDatabaseAutoGrowthSettings(SPContentDatabase contentDatabase)
        {

            string result = "";
            List<string> fails = new List<string>();

            using (SqlConnection connection = new SqlConnection(contentDatabase.DatabaseConnectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand { Connection = connection, CommandText = String.Format(GET_DATABASE_AUTOGROWTH_SETTINGS, contentDatabase.Name) })
                {

                    SqlDataReader reader = command.ExecuteReader();
                    if (reader != null && reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            int type = Convert.ToInt32(reader["type"]);
                            string name = reader["name"].ToString();
                            int is_percent_growth = Convert.ToInt32(reader["is_percent_growth"]);
                            double growth = Convert.ToDouble(reader["growth"]);
                            double max_size = Convert.ToDouble(reader["max_size"]);

                            if (type == 0)
                            {
                                // check if the database is using the default settings
                                if (is_percent_growth == 0 && growth == 1.0)
                                {
                                    // default setttings are in place
                                    fails.Add("Rows Data");
                                }
                            }
                            else
                            {
                                // check if the database is using the default settings
                                if (is_percent_growth == 1 && growth == 10.0)
                                {
                                    // default setttings are in place
                                    fails.Add("Logs");
                                }
                            }
                        }
                    }
                }
            }

            foreach (string fail in fails)
            {
                result += fail + ", ";
            }
            if (result.EndsWith(", "))
                result = result.Substring(0, result.Length - 2);

            return result;

        }
        #endregion

    }
}
